#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <imgproc/imgproc_c.h>

using namespace cv;
using namespace std;

Mat src;
Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);
Mat ellipseMat,finalResultMat;

Vector<RotatedRect> distinctedBiggerEllipses;

/// Function header
int thresh_callbackxxx();

void putIntoEllipsesAndDistinct(RotatedRect re);

//g++ fileellipse3.cpp -o fileell3 $O_LIBS
//./a.out 1 50 11
/** @function main */
int main(int argc, char** argv) {
	/// Load source image and convert it to gray
	src = imread(argv[1], 1);

	//try to creat a sub image
//	savesubImagepMat(src);

//	IplImage* srcddd;
//	srcddd = cvLoadImage( argv[1]); //加载灰度图
//	savesubMatip(srcddd);

	//savesubMat(src);

	/// Convert image to gray and blur it
	cvtColor(src, src_gray, CV_BGR2GRAY);
	GaussianBlur(src_gray, src_gray, Size(3, 3), 0, 0);

	/// Create Window
	char* source_window = "Source";
	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
	imshow(source_window, src);

//	createTrackbar(" Threshold:", "Source", &thresh, max_thresh,
//			thresh_callback);
//	thresh_callback(0, 0);

	distinctedBiggerEllipses = Vector<RotatedRect>();//(1000);

	ellipseMat = Mat::zeros(src_gray.size(), CV_8UC3);
	//drawing2 = Mat::zeros(src_gray.size(), CV_8UC3);
	finalResultMat = src.clone();
	for(int i = 15; i < 200; i++){
		thresh = i;
		thresh_callbackxxx();

	}

	/// Show in a window
	namedWindow("Contours", CV_WINDOW_AUTOSIZE);
	imshow("Contours", ellipseMat);


	namedWindow("Contours1", CV_WINDOW_AUTOSIZE);
	imshow("Contours1", finalResultMat);

	waitKey(0);
	return (0);
}

bool wayToSort(RotatedRect i, RotatedRect j) { return i.angle > j.angle; }

int thresh_callbackxxx() {
	Mat threshold_output;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	cout << thresh << endl;
	/// Detect edges using Threshold
	threshold(src_gray, threshold_output, thresh, 255, THRESH_BINARY);
	/// Find contours
	findContours(threshold_output, contours, hierarchy, CV_RETR_TREE,
			CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	/// Find the rotated rectangles and ellipses for each contour
	vector<RotatedRect> minRect(contours.size());
	vector<RotatedRect> ellipseList(contours.size());

	for (int i = 0; i < contours.size(); i++) {
		minRect[i] = minAreaRect(Mat(contours[i]));
		if (contours[i].size() > 5) {
			ellipseList[i] = fitEllipse(Mat(contours[i]));
		}
	}

	for (int i = 0; i < contours.size(); i++) {//i is for bigger ellipse
		if(ellipseList[i].size.height > src_gray.size().height/2){//if it is too big
			continue;
		}
		int counter = 0;
		vector<RotatedRect> smallerEllipseList;
		for (int j = 0; j < contours.size(); j++) {// j is for smaller ellipse
			if (j == i) {
				continue;
			}
			float lefttopx = ellipseList[i].center.x - ellipseList[i].size.width/ 2;
			float lefttopy = ellipseList[i].center.y - ellipseList[i].size.height/ 2;
			float rightBottomx = ellipseList[i].center.x + ellipseList[i].size.width / 2;
			float rightBottomy = ellipseList[i].center.y + ellipseList[i].size.height / 2;

			if (ellipseList[j].center.y < rightBottomy && ellipseList[j].center.y > lefttopy) {//check if j's center is inset of i
				if (ellipseList[j].center.x < rightBottomx && ellipseList[j].center.x > lefttopx) {


					float isize = ellipseList[i].size.height * ellipseList[i].size.width;
					float jsize = ellipseList[i].size.height * ellipseList[i].size.width;
					//i did not user the size.
					// i used the height only.
					if(ellipseList[j].size.height < ellipseList[i].size.height/3 && ellipseList[j].size.height > ellipseList[i].size.height/8){
						counter++;//if i can find one small ellipse inset of this big ellipse then counter++
						smallerEllipseList.push_back(ellipseList[j]);
					}
				}
			}

		}
		if(counter > 5){//if we can see more than 5 smaller ellipse then that should be the pattern we are seeking for.
			putIntoEllipsesAndDistinct(ellipseList[i]);//store the big ellipse, and later use to draw result to origianl picture.
			Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
											rng.uniform(0, 255));
			ellipse( ellipseMat, ellipseList[i], color, 8, 8 );//we still inset of the loop, and i is the big ellipse.
			// i did a lot of effort on this, to remove some noise.
			// 1, ignore the horizontal and vertical small ellipses,
			//because noize usually make by clear things which usually have clear horizontal and vertical shapes.(but the upper loop is the right place to do this)
			// 2, also, all smaller ellipses should locate homogeneously around a center, not only the location but also the angle.
			//that is why i try to sort them by angle.
			sort(smallerEllipseList.begin(), smallerEllipseList.end(), wayToSort);
			for(int k = 0; k<smallerEllipseList.size();k++){
				ellipse( ellipseMat, smallerEllipseList[k], color, 3, 8 );//draw the smaller ellipse.
			}
		}

//		if(counter > 5){
////			ellipse( drawing, minEllipse[i], color, 8, 8 );
//			putIntoEllipses(minEllipse[i]);
//			//TODO send this to vote system.
//			//sorted by angle
////			sort(okokokoko.begin(), okokokoko.end(), wayToSort);
////
////			for(int k = 0; k<okokokoko.size();k++){
////				ellipse( drawing, okokokoko[k], color, 3, 8 );
////				// angle
////			}
//
//
//		}
	}

	for (int i = 0; i < distinctedBiggerEllipses.size(); i++) {
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255),rng.uniform(0, 255));
		ellipse( finalResultMat, distinctedBiggerEllipses[i], color, 8, 8 );
		rectangle(finalResultMat,distinctedBiggerEllipses[i].boundingRect(), color, 8, 8);
		//send the ellipses[i] to Odysseas's code
	}


}

void putIntoEllipsesAndDistinct(RotatedRect re){
	Vector<RotatedRect> tempEllipses(distinctedBiggerEllipses);
	int flag = 0;
	for(int i = 0; i<tempEllipses.size(); i++){
		RotatedRect ell = tempEllipses[i];
		int rex = re.center.x - re.size.width/2;
		int rey = re.center.y - re.size.height/2;
		int recx = re.center.x;
		int recy = re.center.y;

		int rex2 = rex + re.size.width;
		int rey2 = rey + re.size.height;
		int res = re.size.width * re.size.height;

		int ellx = ell.center.x - ell.size.width/2;
		int elly = ell.center.y - ell.size.height/2;
		int ellcx = ell.center.x;
		int ellcy = ell.center.y;

		int ellx2 = ellx + ell.size.width;
		int elly2 = elly + ell.size.height;
		int ells = ell.size.width * ell.size.height;

		if(ellcx > rex && ellcx < rex2 && ellcy > rey && ellcy < rey2){
			if(res >= ells){
				distinctedBiggerEllipses[i] = re;
				break;
			}
			flag = 1;
		}else if(recx > ellx && recx < ellx2 && recy > elly && recy < elly2){
			if(res >= ells){
				distinctedBiggerEllipses[i] = re;
				break;
			}
			flag = 1;
		}
	}
	if(flag == 0){
		distinctedBiggerEllipses.push_back(re);
	}

}

